// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { Button, CheckBox, ListView, Palette, ScrollView, LineEdit } from "std-widgets.slint";
import { EditorFontSettings, EditorSizeSettings, EditorSpaceSettings, EditorPalette } from "./styling.slint";
import { Api, SelectionStackFrame, SelectionStackFilter } from "../api.slint";
import { Icons } from "styling.slint";

component FilterList {
    public function show() { pop.show(); }
    public function close() { pop.close(); }

    out property <SelectionStackFilter> filter: {
        if (!self.filter-layout && !self.filter-interactive && self.filter-other) {
            return SelectionStackFilter.Others;
        } else if (!self.filter-layout && self.filter-interactive && !self.filter-other) {
            return SelectionStackFilter.Interactive;
        } else if (!self.filter-layout && self.filter-interactive && self.filter-other) {
            return SelectionStackFilter.InteractiveAndOthers;
        } else if (self.filter-layout && !self.filter-interactive && !self.filter-other) {
            return SelectionStackFilter.Layouts;
        } else if (self.filter-layout && !self.filter-interactive && self.filter-other) {
            return SelectionStackFilter.LayoutsAndOthers;
        } else if (self.filter-layout && self.filter-interactive && !self.filter-other) {
            return SelectionStackFilter.LayoutsAndInteractive;
        } else if (self.filter-layout && self.filter-interactive && self.filter-other) {
            return SelectionStackFilter.Everything;
        }
        return SelectionStackFilter.Nothing;
    }
    out property <bool> has-filter: !self.filter-layout || !self.filter-interactive || !self.filter-other;

    in-out property <bool> filter-interactive: true;
    in-out property <bool> filter-layout: true;
    in-out property <bool> filter-other: true;

    width: 0px;
    height: 0px;

    pop := PopupWindow {
        width: self.preferred-width;
        height: self.preferred-height;

        close-policy: PopupClosePolicy.close-on-click-outside;

        Rectangle {
            border-color: Palette.border;
            border-width: 1px;
            border-radius: EditorSizeSettings.radius;

            drop-shadow-blur: EditorSpaceSettings.default-padding;
            drop-shadow-color: Palette.foreground.transparentize(0.9);

            background: Palette.alternate-background;

            TouchArea {
                // Just block events from reaching other TouchAreas!
            }

            VerticalLayout {
                padding: EditorSpaceSettings.default-padding;
                spacing: EditorSpaceSettings.default-spacing;

                lcb := CheckBox {
                    text: @tr("Layouts");
                    checked <=> root.filter-layout;
                }

                icb := CheckBox {
                    text: @tr("Interactive");
                    checked <=> root.filter-interactive;
                }

                ocb := CheckBox {
                    text: @tr("Other");
                    checked <=> root.filter-other;
                }
            }
        }
    }
}

component PopupInner inherits Rectangle {
    in property <length> preview-width: 500px;
    in property <length> preview-height: 900px;

    callback close();

    in-out property <bool> filter-interactive: true;
    in-out property <bool> filter-layout: true;
    in-out property <bool> filter-other: true;
    in-out property <string> filter-text: "";

    in property <length> max-popup-height: 900px;
    in-out property <length> selection-x: 0px;
    in-out property <length> selection-y: 0px;
    in-out property <[SelectionStackFrame]> selection-stack: [
        {
            width: 100%,
            height: 40%,
            x: 10%,
            y: 0%,
            is-in-root-component: true,
            is-layout: false,
            is-interactive: true,
            is-selected: false,
            type-name: "TypeA",
            file-name: "thumb.slint",
            id: "some_a",
        },
        {
            width: 50%,
            height: 50%,
            x: 0%,
            y: 0%,
            is-in-root-component: false,
            is-layout: true,
            is-interactive: false,
            is-selected: false,
            file-name: "thumb.slint",
            type-name: "HorizontalLayout",
        },
        {
            width: 50%,
            height: 10%,
            x: 20%,
            y: 40%,
            is-in-root-component: false,
            is-layout: false,
            is-interactive: false,
            is-selected: false,
            type-name: "Rectangle",
            file-name: "tiling.slint",
            id: "",
        },
        {
            width: 50%,
            height: 50%,
            x: 50%,
            y: 50%,
            is-in-root-component: false,
            is-interactive: false,
            is-selected: true,
            type-name: "TypeA",
            file-name: "finger.slint",
            id: "some_a",
        },
        {
            width: 250%,
            height: 50%,
            x: 50%,
            y: 50%,
            is-in-root-component: false,
            is-layout: false,
            is-interactive: true,
            is-selected: false,
            type-name: "Button",
            file-name: "finger.slint",
            id: "alsoInteractive",
        },
        {
            width: 50%,
            height: 50%,
            x: 0%,
            y: 50%,
            is-in-root-component: false,
            is-layout: true,
            is-interactive: false,
            is-selected: false,
            file-name: "finger.slint",
            type-name: "VerticalLayout",
        },
        {
            width: 5%,
            height: 5%,
            x: 25%,
            y: 25%,
            is-in-root-component: true,
            is-layout: false,
            is-interactive: false,
            is-selected: false,
            id: "words",
            type-name: "Text",
        },
        {
            width: 50%,
            height: 100%,
            x: 0%,
            y: 0%,
            is-in-root-component: true,
            is-layout: false,
            is-interactive: false,
            is-selected: false,
            type-name: "Window",
            id: "",
        }
    ];

    private property <SelectionStackFrame> select-on-close: Api.find-selected-selection-stack-frame(self.selection-stack);

    private property <float> aspect-ratio: preview-width / preview-height;

    private property <length> max-rect-size: 40px;
    private property <length> frame-height: self.max-rect-size + EditorSpaceSettings.default-padding * 2 + 1rem;
    private property <int> max-visible-frames: Math.floor(((self.max-popup-height / 1px) * 0.8) / (self.frame-height / 1px));
    private property <int> visible-frames: Math.min(self.max-visible-frames, root.selection-stack.length);

    function unselect-previewed-selection() {
        if self.select-on-close.element-path != "" {
            Api.select-element(self.select-on-close.element-path, self.select-on-close.element-offset, self.select-on-close.x * root.preview-width, self.select-on-close.y * root.preview-height);
        }
    }

    private property <[SelectionStackFrame]> filtered-model: Api.filter-sort-selection-stack(root.selection-stack, filter-edit.text, filter-list.filter);
    border-radius: EditorSizeSettings.radius;

    border-width: 0.5px;
    background: Palette.background;
    drop-shadow-blur: 10px;
    drop-shadow-color: black;
    border-color: lightgray;

    width: 250px;

    TouchArea {
        changed has-hover => {
            if self.has-hover {
                root.unselect-previewed-selection();
            }
        }
    }

    VerticalLayout {
        spacing: EditorSpaceSettings.default-spacing;

        header := HorizontalLayout {
            padding: EditorSpaceSettings.default-padding;
            padding-bottom: 0px;
            spacing: EditorSpaceSettings.default-spacing;

            filter-button := Button {
                private property <bool> filter-state: filter-list.filter != SelectionStackFilter.Everything || filter-edit.text != "";

                changed filter-state => {
                    self.checked = filter-state;
                }

                icon: Icons.filter;
                checkable: true;
                colorize-icon: true;

                clicked => {
                    filter-list.show();
                    filter-edit.clear-focus();
                    self.checked = filter-state;
                }

                init => {
                    self.checked = filter-state;
                }
            }

            filter-edit := LineEdit {
                placeholder-text: "Filter";
                min-width: 50px;
                text <=> root.filter-text;
                init => {
                    self.focus();
                }

                changed has-focus => {
                    if !self.has-focus {
                        self.focus();
                    }
                }
            }
        }

        Rectangle {
            VerticalLayout {
                if filtered-model.length == 0: Rectangle {
                    width: 100%;
                    height: (root.visible-frames * root.frame-height);

                    Text {
                        text: @tr("No match");
                    }
                }

                if filtered-model.length >= 1: ScrollView {
                    height: (root.visible-frames * root.frame-height);

                    list-view := VerticalLayout {
                        for frame[index] in root.filtered-model: frame-rect := Rectangle {
                            height: root.frame-height;

                            function frame-color(frame: SelectionStackFrame) -> brush {
                                return EditorPalette.interactive-element-selection-secondary;
                            }
                            function frame-background(frame: SelectionStackFrame) -> brush {
                                if frame.is-interactive {
                                    return EditorPalette.interactive-element-selection-primary;
                                } else if frame.is-layout {
                                    return transparent;
                                } else if frame.is-selected {
                                    EditorPalette.general-element-selection-selected;
                                } else {
                                    return EditorPalette.general-element-selection-primary;
                                }
                            }
                            function calculate_pos(p: length, percent: float) -> length {
                                return Math.round((p / 1px) * percent) * 1px;
                            }
                            function calculate_size(p: length, percent: float) -> length {
                                return Math.max(Math.round((p / 1px) * percent), 2) * 1px;
                            }
                            VerticalLayout {
                                padding-top: EditorSpaceSettings.default-padding / 2;
                                if !frame.is-in-root-component: Text {
                                    x: EditorSpaceSettings.default-padding;
                                    text: frame.file-name;
                                    overflow: elide;
                                    color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
                                    font-size: EditorFontSettings.label-sub.font-size - 3px;
                                    font-italic: true;
                                }

                                HorizontalLayout {
                                    visible: (frame.type-name == "Window") ? false : true;
                                    padding-left: EditorSpaceSettings.default-padding;
                                    spacing: EditorSpaceSettings.default-spacing / 2.0;
                                    alignment: start;

                                    VerticalLayout {
                                        alignment: center;
                                        padding-bottom: EditorSpaceSettings.default-padding / 2;

                                        Rectangle {
                                            function calculate_aspect_ratio_box(aspect-ratio: float, max-rect-length: length) -> length {
                                                return Math.min(aspect-ratio, 1.0) * max-rect-length;
                                            }
                                            clip: true;
                                            width: calculate_aspect_ratio_box(root.aspect-ratio, root.max-rect-size) + EditorSpaceSettings.default-padding;
                                            height: calculate_aspect_ratio_box(1.0 / root.aspect-ratio, root.max-rect-size) + EditorSpaceSettings.default-padding / 2;
                                            measure-rect := Rectangle {
                                                width: calculate_aspect_ratio_box(root.aspect-ratio, root.max-rect-size);
                                                height: calculate_aspect_ratio_box(1.0 / root.aspect-ratio, root.max-rect-size);

                                                border-color: frame.is-selected ? EditorPalette.general-element-selection-selected.transparentize(0.5) : Palette.foreground.transparentize(0.65);
                                                border-width: 1px;
                                                placeholder-rect := Rectangle {
                                                    x: calculate_pos(measure-rect.width, frame.x);
                                                    y: calculate_pos(measure-rect.height, frame.y);
                                                    width: calculate_size(measure-rect.width, frame.width);
                                                    height: calculate_size(measure-rect.height, frame.height);

                                                    border-color: frame-rect.frame-color(frame);
                                                    border-width: 0.5px;
                                                    background: frame-rect.frame-background(frame);
                                                    if frame.is-layout: Rectangle {
                                                        border-color: EditorPalette.layout-element-selection-secondary;
                                                        border-width: 0.5px;
                                                        if (frame.type-name == "HorizontalLayout" || frame.type-name == "HorizontalBox"): HorizontalLayout {
                                                            spacing: 1px;
                                                            padding: 1px;

                                                            Rectangle {
                                                                background: EditorPalette.layout-element-selection-primary;
                                                            }

                                                            Rectangle {
                                                                background: EditorPalette.layout-element-selection-primary;
                                                            }
                                                        }

                                                        if (frame.type-name == "VerticalLayout" || frame.type-name == "VerticalBox"): VerticalLayout {
                                                            spacing: 1.5px;
                                                            padding: 1.5px;

                                                            Rectangle {
                                                                background: EditorPalette.layout-element-selection-primary;
                                                            }

                                                            Rectangle {
                                                                background: EditorPalette.layout-element-selection-primary;
                                                            }
                                                        }
                                                        if (frame.type-name == "GridLayout" || frame.type-name == "GridBox"): VerticalLayout {
                                                            spacing: 1px;
                                                            HorizontalLayout {
                                                                spacing: 1.5px;
                                                                padding: 1.5px;
                                                                Rectangle {
                                                                    background: EditorPalette.layout-element-selection-primary;
                                                                }

                                                                Rectangle {
                                                                    background: EditorPalette.layout-element-selection-primary;
                                                                }
                                                            }

                                                            HorizontalLayout {
                                                                spacing: 1.5px;
                                                                padding: 1.5px;
                                                                Rectangle {
                                                                    background: EditorPalette.layout-element-selection-primary;
                                                                }

                                                                Rectangle {
                                                                    background: EditorPalette.layout-element-selection-primary;
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    VerticalLayout {
                                        spacing: EditorSpaceSettings.default-spacing / 2;
                                        alignment: center;

                                        if frame.id != "": Text {
                                            text: frame.id;
                                            overflow: elide;
                                            color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
                                            font-weight: EditorFontSettings.bold-font-weight;
                                            font-size: EditorFontSettings.label.font-size;
                                        }

                                        Text {
                                            text: frame.type-name;
                                            overflow: elide;
                                            color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
                                            font-size: EditorFontSettings.label-sub.font-size;
                                            font-italic: true;
                                        }
                                    }
                                }

                                Rectangle {
                                    height: 1px;
                                    background: Palette.border;
                                }
                            }

                            x: -EditorSpaceSettings.default-padding / 2;
                            border-width: 0px;
                            states [
                                hover when ta.has-hover && !frame.is-selected: {
                                    background: Palette.accent-background.transparentize(0.9);
                                }
                                unhover when !ta.has-hover && !frame.is-selected: {
                                    background: Palette.background;
                                }
                                selected when frame.is-selected: {
                                    background: Palette.accent-background;
                                }
                            ]

                            ta := TouchArea {
                                clicked() => {
                                    Api.select-element(frame.element-path, frame.element-offset, frame.x * root.preview-width, frame.y * root.preview-height);
                                    root.select-on-close = { };
                                    root.close();
                                }
                                changed has-hover => {
                                    if self.has-hover {
                                        Api.select-element(frame.element-path, frame.element-offset, frame.x * root.preview-width, frame.y * root.preview-height);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Rectangle {
                height: 3px;
                y: 0px;
                width: 100%;
                background: EditorPalette.shadow-gradient;
            }
        }
    }

    filter-list := FilterList {
        x: filter-button.x + EditorSpaceSettings.default-spacing;
        y: filter-button.y + filter-button.height + EditorSpaceSettings.default-spacing;

        filter-layout <=> root.filter-layout;
        filter-interactive <=> root.filter-interactive;
        filter-other <=> root.filter-other;
    }
}

export component SelectionPopup {
    public function show-selection-stack(x: length, y: length) {
        self.selection-x = x;
        self.selection-y = y;
        self.selection-stack = Api.selection-stack-at(self.selection-x, self.selection-y);

        popup.show();
    }

    in property <length> preview-width;
    in property <length> preview-height;
    in property <length> max-popup-height;
    private property <[SelectionStackFrame]> selection-stack;
    private property <length> selection-x;
    private property <length> selection-y;

    private property <bool> filter-interactive: true;
    private property <bool> filter-layout: true;
    private property <bool> filter-other: true;
    private property <string> filter-text: "";

    popup := PopupWindow {
        in property <length> preview-width: root.preview-width;
        in property <length> preview-height: root.preview-height;
        in-out property <[SelectionStackFrame]> selection-stack: root.selection-stack;
        in-out property <length> selection-x: root.selection-x;
        in-out property <length> selection-y: root.selection-y;
        in property <length> max-popup-height: root.max-popup-height;

        in-out property <bool> filter-interactive <=> root.filter-interactive;
        in-out property <bool> filter-layout <=> root.filter-layout;
        in-out property <bool> filter-other <=> root.filter-other;
        in-out property <string> filter-text <=> root.filter-text;

        close-policy: PopupClosePolicy.close-on-click-outside;

        max-height: root.max-popup-height;

        x: root.selection-x + 10px;
        y: root.selection-y + 10px;

        VerticalLayout {
            inner := PopupInner {
                close() => {
                    popup.close();
                }

                filter-text <=> popup.filter-text;
                filter-layout <=> popup.filter-layout;
                filter-interactive <=> popup.filter-interactive;
                filter-other <=> popup.filter-other;

                preview-width <=> popup.preview-width;
                preview-height <=> popup.preview-height;

                max-popup-height <=> popup.max-popup-height;
                selection-stack <=> popup.selection-stack;
                selection-x <=> popup.selection-x;
                selection-y <=> popup.selection-y;
            }
        }
    }
}
